此部分感謝 c.c.Liang 老師指導!
在進入 Provider 與 Signer 之前需要提起三個問題:
在最早期的時候以太坊希望「每個人」都會自己跑 geth 這樣的全節點,然後使用 mist 與其他人進行 p2p 互動,因此上述三個步驟都是全節點負責。這也能顯示為什麼 web3.js 裡面的 provider 會把上述三個步驟全部包起來,導致使用節點商服務的時候會因為沒有私鑰產生錯誤。
例如 web3.eth.personal.newAccount 這個 API 是呼叫 geth 的 personal_newaccount,Geth 會產生一個私鑰,並且用 passphrase 加密。然後 web3.eth.personal.unlockAccount
指定地址和 passphrase 解鎖,Geth 會解密出私鑰再做簽章,送交易。
上述例子可以發現三個步驟都是使用 geth 完成。但隨著時間經過節點商慢慢出現,就沒辦法用來儲存私鑰,導致整個送交易的步驟發生錯誤。因此儲存交易的任務就交給了 Metamask 這樣的私鑰管理器負責。也就是 ethers.js 後來區分了新角色的原因: Provider 和 Signer 和 Contract。
節點商可以幫助我們連結到節點「查看」鏈上資訊,例如:Parity, Ganache, Infura, AlchemyAPI
然而節點商不會儲存我們的私鑰,因此沒辦法代替我們送出交易!
那到底為什麼我們可以在瀏覽器中直接使用 window.ethereum
呢,也許可以從 The Ethereum JavaScript provider API is specified by EIP-1193 找到一些端倪。
再來一些名詞定義:
在這邊我們使用 MetaMask 作為我們的 provider。除此之外還可以使用 infura 和 etherscan 等。下一個章節 ethers.js
的部分會特別介紹各種 provider。
MetaMask 在我們的網站中建置了全局的 API,所以我們可以藉由 window.ethereum 來訪問節點。這個 API 讓網站可以從區塊鏈上取得使用者的以太坊帳戶(不包含私鑰)、讀取各種資料。並且提供一個媒介讓使用者可以簽核(sign)messages 和 transactions。
在任何平台或者瀏覽器中,MetaMask 官方建議我們使用 @metamask/detect-provider 來檢測 provider,而以 MetaMask 為 provider 互動的對象就是 Ethereum user 的帳戶。
// This function detects most providers injected at window.ethereum
import detectEthereumProvider from '@metamask/detect-provider';
const provider = await detectEthereumProvider();
if (provider) {
// From now on, this should always be true:
// provider === window.ethereum
startApp(provider); // initialize your app
} else {
console.log('Please install MetaMask!');
}
要使任何複雜的 Ethereum 應用程式(例如:dapp, web3 網站)能夠運作,我們會需要達到以下幾點要求:
window.ethereum
)這邊補充一下所有以太坊知名的 network id:
測試網 | Network |
---|---|
Olympic testnet | 0 |
Ethereum Mainnet(frontier) | 1 |
Ethereum’s Morden testnet | 2 |
Ropsten testnet | 3 |
Rinkeby testnet | 4 |
Georli testnet | 5 |
Rootstock Mainnet | 30 |
Rootstock testnet | 31 |
Kovan | 42 |
Ethereum Classic Mainnet | 61 |
Ethereum Classic testnet | 62 |
要建立一個功能齊全的 Web3 Application 最重要的元素就是取得 provider API。
我們目前都是一直使用各種方便的套件像是 ethers 和其他包裝好的模組,而非直接使用 provider 和以太坊節點互動。因為如果需要建置高階抽象的 DAPP,也許使用方便的套件們會更為模組化。
不過還是必須去了解他們背後運作的原理,才能確保在使用上和安全上都沒有問題。
我們剛剛有提過 RPC(遠端過程調用,Remote Process Call)在 web3 意指的是任何遞交給 Provider 的 request。實際上 RPC 就是在兩台伺服器中,其中一台呼叫另外一台上某個應用的函式或者方法。由於記憶體的不共用,所以 RPC 作為一個訊息傳遞的載體表達 calling 的內容及參數們。
而說到 Ethereum JSON-RPC API,就得先講到 JSON 檔案,JSON 是一個簡單表達資料數據的格式,可以用來表示數值、字符串、陣列和字典(鍵-值對集合,key/value pair set)。
JSON-RPC 則是一種無狀態的輕量級(json 為簡單格式)RPC 協議。這個協議訂立了資料結構和相對應的處理規則,通常用於 HTTP 或各種消息通信環境。
MetaMask 是透過 EIP-2255 協議來執行 Web3 Wallet Permissions 。
在這個核准系統裡面,每個 RPC 方法都有限制或非限制的分別。如果這個方法受到限制,則 caller 必須擁有相對應的核准才可以呼叫它,如果是沒不受限制的方法,則不用相對應的核准就可呼叫。
舉例來說如果有一個 sign 的方法,則我們必須要擁有 signer account 的eth_accounts
同意。有些函式還需要被使用者的確認,像是來自 EIP-3085 的wallet_addEthereumChain
。
以下這個介面(interface)可作為一個範例:
interface Web3WalletPermission {
// The name of the method corresponding to the permission
parentCapability: string;
// The date the permission was granted, in UNIX epoch time
date?: number;
}
通常我們可以自定義每個錢包做為 Provider 的機制,但也可以使用像 Web3Modal 這樣桶裝套件(跟家庭炸雞餐一樣),細細觀察之後會發現其實他幫我們整理了多個錢包做為 Provider 的程式碼。
大部分這個領域的 Dapp 開發者不會碰到底層技術,因此在省下 Web2 的後端資料庫之後,許多人會覺得 Web3 的 Dapp 未免也太簡單了吧,不過就是串個 API 然後狂 Call 函式罷了。但實際上很多事情沒有想像中單純,如果大家並沒有詳細了解 Provider 或 Signer 的概念,也沒有特別著重 Node、Tx、Contract(EVM 相容) 的技術實作內容,也就是我前幾天分享的內容的話,話在 Dapp 開發上會碰到許多困難。
想要更深入或者了解更多的朋友,可以看我在 TEM 的這篇文章 - Transaction, ContractMethods & Provider In Dapp
最後歡迎大家拍打餵食大學生
0x2b83c71A59b926137D3E1f37EF20394d0495d72d